package com.loe.ktui.ui

import android.annotation.SuppressLint
import android.content.Context
import android.content.res.ColorStateList
import android.graphics.*
import android.graphics.drawable.Drawable
import android.text.InputFilter
import android.text.InputType
import android.text.TextUtils.TruncateAt
import android.text.method.DigitsKeyListener
import android.util.AttributeSet
import android.util.TypedValue
import android.view.MotionEvent
import android.view.ViewGroup
import android.widget.EditText
import androidx.core.view.isVisible
import com.loe.ktui.R
import com.loe.ktui.addTextAfterListener
import com.loe.ktui.dist
import com.loe.ktui.distFloat
import com.loe.ktui.util.KtColor
import com.loe.ktui.util.KtDecimalInputFilter
import java.util.*

open class UiEdit(id: String? = null) : UiView(id)
{
    companion object
    {
        const val INPUT_TEXT = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE
        const val INPUT_TEXT_CODE = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
        const val INPUT_DECIMAL = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
        const val INPUT_NUMBER = InputType.TYPE_CLASS_NUMBER
        const val INPUT_PASSWORD = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
    }

    var text: String? = null
    var textColor: Int? = null
    var hint: String? = null
    var hintColor: Int? = null
    var gravity: Int? = null
    var isTextSelectable: Boolean? = null
    var minLines: Int? = null
    var maxLines: Int? = null
    var ellipsis: TruncateAt? = null
    var bold: Boolean? = null
    var italic: Boolean? = null
    var textStyle: String? = null
    var textSize: Any? = null
    var autoVisible: Boolean? = null
    var isClear: Boolean? = null
    var clearColor: Int? = null
    var clearSize: Any? = null
    var inputType: Int? = null
    var limitNumber: Int? = 0
    var limitDecimal: Int? = 0
    var maxLen: Int? = null
    var filter: String? = null

    var onText: (KtEditText.(s: String) -> Unit)? = null
    fun onText(onText: KtEditText.(s: String) -> Unit)
    {
        this.onText = onText
    }

    open fun initUI(context: Context, view: KtEditText)
    {
        super.initUI(context, view)

        isClick?.let { view.setClick(it) }

        text?.let { view.setAutoText(it) }
        view.setTextColor(textColor ?: KtColor.text)
        hint?.let { view.hint = it }
        hintColor?.let { view.setHintTextColor(it) }
        gravity?.let { view.gravity = it }
        isTextSelectable?.let { view.setTextIsSelectable(it) }
        minLines?.let { view.minLines = it }
        maxLines?.let { view.maxLines = it }
        ellipsis?.let { view.ellipsize = it }
        bold?.let { view.setBold(it) }
        italic?.let { view.setItalic(it) }
        textStyle?.let { view.setTextStyle(it) }
        hintColor?.let { view.setHintTextColor(it) }
        textSize?.let { view.setTextSize(TypedValue.COMPLEX_UNIT_PX, it.distFloat) }
        autoVisible?.let { view.isAutoVisible = it }
        isClear?.let { view.initClear(it, (clearSize ?: 24).dist, clearColor) }
        inputType?.let { view.inputType = it }

        limitNumber?.let { view.limitNumber = it }
        limitDecimal?.let { view.limitDecimal = it }
        maxLen?.let { view.maxLenFilter = InputFilter.LengthFilter(it) }

        filter?.let { view.setFilter(it) }

        onText?.let { onText -> view.setTextListener { view.onText(it) } }
    }

    /** 创建view */
    override fun createView(context: Context, parent: ViewGroup?): KtEditText
    {
        return KtEditText(context).also()
        {
            initUI(context, it)
            addToParent(parent, it)
        }
    }
}

fun Any.ui_Edit(id: String? = null, block: (UiEdit.() -> Unit)? = null): UiEdit
{
    val ui = UiEdit(id)
    block?.let { ui.it() }
    if (this is UiGroup) addChild(ui)
    return ui
}

@SuppressLint("AppCompatCustomView")
open class KtEditText : EditText
{
    constructor(context: Context) : super(context)

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
    {
        initXML(attrs)
    }

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
    {
        initXML(attrs)
    }

    private fun initXML(attrs: AttributeSet)
    {
    }

    init
    {
        setBackgroundColor(Color.TRANSPARENT)
    }

    /******************************************* 清除 *******************************************/

    private var isClear = false

    internal fun initClear(isClear: Boolean, clearSize: Int, clearColor: Int? = null)
    {
        this.isClear = isClear
        if (!isClear) return

        var clearDrawable = compoundDrawables[2]
        if (clearDrawable == null)
        {
            clearDrawable = resources.getDrawable(R.mipmap.kt_icon_clear_gray, context.theme)
        }
        clearDrawable.setBounds(0, 0, clearSize, clearSize)
        if (clearColor != null) clearDrawable.colorFilter = PorterDuffColorFilter(clearColor, PorterDuff.Mode.SRC_ATOP)

        fun setClearIconVisible(visible: Boolean)
        {
            val right: Drawable? = if (visible) clearDrawable else null
            setCompoundDrawables(compoundDrawables[0], compoundDrawables[1], right, compoundDrawables[3])
        }

        // 默认设置隐藏图标
        setClearIconVisible(false)
        // 设置焦点改变的监听
        var hasFocus = false
        // 设置输入框里面内容发生改变的监听
        setOnFocusChangeListener()
        { v, hFocus ->
            hasFocus = hFocus
            setClearIconVisible(hasFocus && text.isNotEmpty())
        }
        addTextAfterListener()
        {
            if (hasFocus)
            {
                setClearIconVisible(text.isNotEmpty())
            }
        }
    }

    override fun onTouchEvent(event: MotionEvent): Boolean
    {
        if (isClear && event.action == MotionEvent.ACTION_UP)
        {
            if (compoundDrawables[2] != null)
            {
                val touchable = event.x > width - totalPaddingRight &&
                    event.x < width - paddingRight
                if (touchable)
                {
                    setText("")
                }
            }
        }
        return super.onTouchEvent(event)
    }

    /******************************************* 处理 *******************************************/

    internal var maxLenFilter: InputFilter? = null
    internal var limitNumber: Int = 0
    internal var limitDecimal: Int = 0

    fun setLimitNumber(limitNumber: Int)
    {
        this.limitNumber = limitNumber
        resetLimit()
    }

    fun setLimitDecimal(limitDecimal: Int)
    {
        this.limitDecimal = limitDecimal
        resetLimit()
    }

    fun setMaxLen(max: Int)
    {
        maxLenFilter = InputFilter.LengthFilter(max)
        resetLimit()
    }

    private fun resetLimit()
    {
        val filters = ArrayList<InputFilter>()
        if (maxLenFilter != null)
        {
            filters.add(maxLenFilter!!)
        }
        if (limitNumber > 0 || limitDecimal > 0)
        {
            filters.add(KtDecimalInputFilter(limitNumber, limitDecimal))
        }
        if (filters.isNotEmpty()) setFilters(filters.toTypedArray())
    }

    fun setFilter(s: String)
    {
        keyListener = DigitsKeyListener.getInstance(s)
    }

    /******************************************* 其他 *******************************************/

    var isAutoVisible: Boolean = false

    fun setAutoText(s: String?)
    {
        if (isAutoVisible) isVisible = s == null || s.trim().isEmpty()
        setText(s)
    }

    fun setClick(isClick: Boolean)
    {
        isAlpha = isClick
        isClickable = isClick
    }

    private var isAlpha = false

    override fun setTextColor(color: Int)
    {
        if (isAlpha)
        {
            val states = arrayOfNulls<IntArray>(3)
            states[0] = intArrayOf(android.R.attr.state_enabled, -android.R.attr.state_pressed)
            states[1] = intArrayOf(android.R.attr.state_enabled, android.R.attr.state_pressed)
            states[2] = intArrayOf(-android.R.attr.state_enabled)
            val alphaColor = (0xbb shl 24) + (color and 0xFFFFFF)
            setTextColor(ColorStateList(states, intArrayOf(color, alphaColor, alphaColor)))
        } else
        {
            super.setTextColor(color)
        }
    }

    private var onText: ((s: String) -> Unit)? = null

    private val addTextChanged by lazy {
        addTextAfterListener()
        {
            onText?.invoke(it)
        }
    }

    fun setTextListener(onText: (s: String) -> Unit)
    {
        this.onText = onText
        addTextChanged
    }

    fun focus()
    {
        isFocusable = true
        isFocusableInTouchMode = true
        clearFocus()
        requestFocus()
        setSelection(text.length)
    }

    /***************************************** 文本样式 ***************************************/

    fun setBold(bold: Boolean)
    {
        typeface = if (bold) Typeface.DEFAULT_BOLD else Typeface.DEFAULT
    }

    fun setItalic(italic: Boolean)
    {
        setTypeface(Typeface.DEFAULT, if (italic) Typeface.ITALIC else Typeface.NORMAL)
    }

    fun setTextStyle(textStyle: String)
    {
        when (textStyle)
        {
            "bold" -> paint.flags = Paint.FAKE_BOLD_TEXT_FLAG or Paint.ANTI_ALIAS_FLAG
            "delete" -> paint.flags = Paint.STRIKE_THRU_TEXT_FLAG or Paint.ANTI_ALIAS_FLAG
            "under" -> paint.flags = Paint.UNDERLINE_TEXT_FLAG or Paint.ANTI_ALIAS_FLAG
            // normal
            else -> paint.flags = Paint.ANTI_ALIAS_FLAG
        }
    }

    fun setTextSize(size: Any)
    {
        if (size is Double)
        {
            setTextSize(TypedValue.COMPLEX_UNIT_DIP, size.toFloat())
        } else
        {
            setTextSize(TypedValue.COMPLEX_UNIT_PX, size.toString().toFloat())
        }
    }

    companion object
    {
        val INPUT_TEXT = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE
        val INPUT_TEXT_CODE = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
        val INPUT_DECIMAL = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
        val INPUT_NUMBER = InputType.TYPE_CLASS_NUMBER
        val INPUT_PASSWORD = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
    }
}